import requests
import json
import random
from py2neo import Graph

from intent.sklearn.clf_model import CLFModel
from utils.json_utils import dump_user_dialogue_context, load_user_dialogue_context
from config import *

graph = Graph(host="127.0.0.1",
            http_port=7474,
            user="neo4j",
            password="123456")
clf_model = CLFModel('./intent/sklearn/model_file/')

def intent_classifier(text):
    """
    通过post方式请求医疗意图识别分类服务
    基于bert+textcnn实现
    :param text:
    :return:
    """
    url = "http://127.0.0.1:60062/service/api/bert_intent_recognize"
    data = {"text":text}
    headers = {'Content-Type':'application/json;charset=utf8'}
    response = requests.post(url, data=json.dumps(data), headers=headers)
    if response.status_code == 200:
        response = json.loads(response.text)
        return response["data"]
    else:
        return -1

def slot_recognizer(text):
    url = 'http://127.0.0.1:60061/service/api/medical_ner'
    data = {"text_list":[text]}
    headers = {'Content-Type':'application/json;charset=utf8'}
    reponse = requests.post(url,data=json.dumps(data),headers=headers)
    if reponse.status_code == 200:
        reponse = json.loads(reponse.text)
        return reponse['data']
    else:
        return -1

def classifier(text):
    # 初步判断用户输入的意图，如果是闲聊则还需区分什么类型的闲聊
    # 如果是诊断或者是确认的意图 就进入医疗问答模块
    return clf_model.predict(text)

def neo4j_searcher(cql_list):
    ress = ""
    # 如果存在多个查询语句 需要每一句查询并存储每一句的查询结果
    if isinstance(cql_list,list):
        for cql in cql_list:
            rst = []
            data = graph.run(cql).data()
            if not data:
                continue
            for d in data:
                d = list(d.values())
                if isinstance(d[0], list):
                    rst.extend(d[0])
                else:
                    rst.extend(d)

            data = "、".join([str(i) for i in rst])
            ress += data+"\n"

    else:
        data = graph.run(cql_list).data()
        if not data:
            return ress
        rst =[]
        for d in data:
            d = list(d.values())
            if isinstance(d[0],list):
                rst.extend(d[0])
            else:
                rst.extend(d)
        data = "、".join([str(i) for i in rst])
        ress += data + "\n"

    return ress

def semantic_parser(text, user):
    # 对用户输入文本确定实体和问题类型
    # 匹配对应模板填槽回复

    # 确定用户问题意图进行分类
    intent_receive = intent_classifier(text) #得到用户问题类型，返回结果有匹配度和问题类型
    print("intent_receive:", intent_receive)

    # 确定用户问题中的实体
    slot_receive = slot_recognizer(text)
    print("slot_receive:", slot_receive)

    #如果服务器是无反应则会返回-1值，或者是问题意图是其他，则抽取“不会回答”的回复模板
    if intent_receive == -1 or intent_receive.get("intent") == "其他":
        return semantic_slot.get("unrecognized")

    print("intent:", intent_receive.get("intent"))
    slot_info = semantic_slot.get(intent_receive.get("intent"))
    if slot_receive != -1:
        for entities_info in slot_receive:
            for entity in entities_info["entities"]:
                if entity["type"] == 'symptom' and intent_receive.get("intent") == "临床表现(病症表现)":
                    slot_info = semantic_slot.get("临床表现（病症表现）2")

    print("slot_info:", slot_info)

    # 填槽
    slots = slot_info.get("slot_list")
    print("slots:",slots)

    slot_values = {}
    for slot in slots:
        slot_values[slot] = None
        if slot_receive != -1:
            for entities_info in slot_receive:
                for entity in entities_info["entities"]:
                    # 当前选取的模板类型与问句实体类型一致则保存实体
                    if slot.lower() == entity["type"] and slot_values[slot] is None:
                        # slot_values[slot] = entity_link(entity["word"], entity["type"])
                        slot_values[slot] = entity["word"]
    print("slot_values",slot_values)
    slot_info["slot_values"] = slot_values

    # 根据意图的置信度来确认回复策略
    conf = intent_receive.get("confidence")
    if conf >= intent_threshold_config["accept"]:
        slot_info["intent_strategy"] = "accept"
    elif conf >= intent_threshold_config["deny"]:
        slot_info["intent_strategy"] = "clarify"
    else:
        slot_info["intent_strategy"] = "deny"

    print("semantic_parser:", slot_info)

    # 加载历史最新一次的问题实体
    last_slot_values = load_user_dialogue_context(user)["slot_values"]
    # # 检查当前是否有实体，如果没有则继承历史最新的实体
    if last_slot_values is None:
        return slot_info
    else:
        for k in slot_values.keys():
            if slot_values[k] is None:
                slot_values[k] = last_slot_values.get(k, None)
        slot_info["slot_values"] = slot_values

    print("slot_value:",slot_values)
    return slot_info

def get_answer(slot_info):
    # 根据不同的回复策略，在neo4j中查询答案
    cql_template = slot_info.get("cql_template")
    reply_template = slot_info.get("reply_template")
    ask_template = slot_info.get("ask_template")
    slot_values = slot_info.get("slot_values")
    strategy = slot_info.get("intent_strategy")

    for k in slot_values.keys():
        if slot_values[k] is None:
            slot_info["replay_answer"] = "暂时不清楚你想问什么哦，换个方式问吧！"
            return slot_info

    if strategy == "accept":
        cql_list =[]
        # 如果查询模板有多个则都需要填入查询的实体
        if isinstance(cql_template,list):
            for cql in cql_template:
                cql_list.append(cql.format(**slot_values))
        else:
            cql_list = cql_template.format(**slot_values)

        answer = neo4j_searcher(cql_list)
        print("neo4j result for accept:", answer)
        if not answer:
            slot_info["replay_answer"] = "唔~我装满知识的大脑此刻很贫瘠"
        elif answer.strip() == "None":
            slot_info["replay_answer"] = "该问题暂时缺乏数据，可以到反馈页面给我的攻城狮留言！我们会尽快完善~"
        else:
            pattern = reply_template.format(**slot_values)
            slot_info["replay_answer"] = pattern + answer

    elif strategy == "clarify":
        # 此时意图置信度在0.2-0.5，需要进行问题澄清
        pattern = ask_template.format(**slot_values)
        print("pattern for clarity:", pattern)

        slot_info["replay_answer"] = pattern
        print("cql_template", cql_template)

        cql_list =[]
        if isinstance(cql_template, list):
            for cql in cql_template:
                cql_list.append(cql.format(**slot_values))
        else:
            cql_list = cql_template.format(**slot_values)

        answer = neo4j_searcher(cql_list)
        print("neo4j result for clarify:", answer)


        # 连不上服务器
        if not answer:
            slot_info["replay_answer"] = "唔~我装满知识的大脑此刻很贫瘠"
            # 数据库不存在相关数据 保存模糊问题的答案用于用户确认问题后回答 choice_answer
        elif answer.strip() == 'None':
            slot_info["choice_answer"] = "该问题暂时缺乏数据，可以到反馈页面给我的攻城狮留言！我们会尽快完善~"
            # 查到结果（理想状态）保存模糊问题的答案用于用户确认问题后回答 choice_answer
        else:
            pattern = reply_template.format(**slot_values)
            slot_info["choice_answer"] = pattern + answer

    elif strategy == "deny":
        slot_info["replay_answer"] = slot_info.get("deny_response")

    print("get_answer:", slot_info)
    return slot_info

def gossip_robot(intent):
    # 调用闲聊模块 随机回复闲聊句子
    return random.choice(
        gossip_corpus.get(intent)
    )

def medical_robot(text, user):
    result = semantic_parser(text, user)
    answer = get_answer(result)
    return answer


